SciChart.js JavaScript 2D Charts API > 2D Chart Types > Series PaletteProvider API > Per-Point Colouring of Scatter Charts (or PointMarkers)
Per-Point Colouring of Scatter Charts (or PointMarkers)

Colouring Scatter Points Individually with PaletteProvider

It is possible to override the Scatter series point-marker fill & stroke colour on a per-datapoint basis in SciChart.js using the PaletteProvider API.

To use this, we must create a class which implements or confirms to the IPointMarkerPaletteProvider interface. Then, apply this to the XyScatterRenderableSeries.paletteProvider property. This allows you to colour data-points based on values, or custom rules with infinite extensiblity.

Let's start off by creating a PaletteProvider class:

const {
  DefaultPaletteProvider,
  EStrokePaletteMode,
  parseColorToUIntArgb
} = SciChart;

// or, for npm, import { DefaultPaletteProvider, ... } from "scichart"

// Custom PaletteProvider for scatter points which colours datapoints above a threshold
class ScatterPaletteProvider extends DefaultPaletteProvider {

  constructor(stroke, fill, rule) {
    super();
    this.strokePaletteMode = EStrokePaletteMode.SOLID;
    this.rule = rule;
    // Use the helper function parseColorToUIntArgb to convert a hex string
    // e.g. #FF00FF77 into ARGB numeric format 0xFF00FF77 expected by scichart
    this.overrideStroke = parseColorToUIntArgb(stroke);
    this.overrideFill = parseColorToUIntArgb(fill);
  }

  // This function is called for every data-point.
  // Return undefined to use the default color for the pointmarker,
  // else, return a custom colour as an ARGB color code, e.g. 0xFFFF0000 is red
  overridePointMarkerArgb(xValue, yValue, index, opacity, metadata) {
    // Draw points outside the range a different color
    if (this.rule(yValue)) {
      return { stroke: this.overrideStroke, fill: this.overrideFill }
    }
    // Undefined means use default colors
    return undefined;
  }
}
It is important that overridePointMarkerArgb returns an object containing both stroke and fill.

 

Next, we can apply the PaletteProvider to a Scatter Series. This can be done both with the programmatic API and the Builder API:

// The ScatterPaletteProvider we created before is applied to a XyScatterRenderableSeries
const scatterSeries = new XyScatterRenderableSeries(wasmContext, {
  dataSeries: new XyDataSeries(wasmContext, { xValues, yValues }),
  pointMarker: new EllipsePointMarker(wasmContext, {
    width: 7,
    height: 7,
    strokeThickness: 1,
    fill: "steelblue",
    stroke: "LightSteelBlue",
  }),
  // PaletteProvider feature allows coloring per-point based on a rule
  paletteProvider: new ScatterPaletteProvider("Red", "Purple", yValue => yValue > 0.0)
});

sciChartSurface.renderableSeries.add(scatterSeries);

// Add this label & annotation to the chart
sciChartSurface.annotations.add(new HorizontalLineAnnotation({ y1: 0, stroke: "#EC0F6C",
  axisLabelFill: "White",
  labelPlacement: ELabelPlacement.BottomRight, labelValue: "Values above this line are red",
  showLabel: true}));
// Register the custom ScatterPaletteProvider with the chartBuilder
chartBuilder.registerType(EBaseType.PaletteProvider, "ScatterPaletteProvider",
    (options) => new ScatterPaletteProvider(options.stroke, options.fill, options.rule));

// Use the Builder-API to build the chart and apply a paletteprovider
const { wasmContext, sciChartSurface } = await chartBuilder.build2DChart(divElementId, {
  surface: { theme: { type: EThemeProviderType.Dark } },
  series: [
    {
      type: ESeriesType.ScatterSeries,
      xyData: {
        xValues,
        yValues,
      },
      options: {
        stroke: "White",
        strokeThickness: 5,
        pointMarker: {
          type: EPointMarkerType.Ellipse,
          options: { width: 7,
            height: 7,
            strokeThickness: 1,
            fill: "steelblue",
            stroke: "LightSteelBlue"
          }
        },
        // Now you can instantiate using parameters below
        paletteProvider: {
          type: EPaletteProviderType.Custom,
          customType: "ScatterPaletteProvider",
          options: {
            stroke: "Red",
            fill: "Purple",
            rule: (yValue) => yValue >= 0.0,
          }
        }
        // Note: Assigning an instance is also valid, e.g.
        // paletteProvider: new ScatterPaletteProvider("Green", "Red", yValue => yValue >= 4.0)
      }
    }
  ],
  annotations: [
    { type: EAnnotationType.RenderContextHorizontalLineAnnotation, options: {
        y1: 0, stroke: "#EC0F6C",
        axisLabelFill: "White",
        labelPlacement: ELabelPlacement.BottomRight, labelValue: "Values above this line are red",
        showLabel: true
      }
    }
  ]
});

 

This results in the following output. Values above 0.0 are coloured red, while values below this threshold use the default colour.

<div id="scichart-root" ></div>
  
body { margin: 0; }
#scichart-root { width: 100%; height: 100vh; }
  
// #region ExampleA
const {
  DefaultPaletteProvider,
  EStrokePaletteMode,
  parseColorToUIntArgb
} = SciChart;

// or, for npm, import { DefaultPaletteProvider, ... } from "scichart"

// Custom PaletteProvider for scatter points which colours datapoints above a threshold
class ScatterPaletteProvider extends DefaultPaletteProvider {

  constructor(stroke, fill, rule) {
    super();
    this.strokePaletteMode = EStrokePaletteMode.SOLID;
    this.rule = rule;
    // Use the helper function parseColorToUIntArgb to convert a hex string
    // e.g. #FF00FF77 into ARGB numeric format 0xFF00FF77 expected by scichart
    this.overrideStroke = parseColorToUIntArgb(stroke);
    this.overrideFill = parseColorToUIntArgb(fill);
  }

  // This function is called for every data-point.
  // Return undefined to use the default color for the pointmarker,
  // else, return a custom colour as an ARGB color code, e.g. 0xFFFF0000 is red
  overridePointMarkerArgb(xValue, yValue, index, opacity, metadata) {
    // Draw points outside the range a different color
    if (this.rule(yValue)) {
      return { stroke: this.overrideStroke, fill: this.overrideFill }
    }
    // Undefined means use default colors
    return undefined;
  }
}
// #endregion

async function drawScatterChartWithPalette(divElementId) {
  // Demonstrates how to create a line chart with PaletteProvider using SciChart.js
  const {
    SciChartSurface,
    NumericAxis,
    XyScatterRenderableSeries,
    XyDataSeries,
    EllipsePointMarker,
    SciChartJsNavyTheme,
    HorizontalLineAnnotation,
    ELabelPlacement
  } = SciChart;

  // or, for npm, import { SciChartSurface, ... } from "scichart"

  const { wasmContext, sciChartSurface } = await SciChartSurface.create(divElementId, {
    theme: new SciChartJsNavyTheme()
  });
  sciChartSurface.xAxes.add(new NumericAxis(wasmContext));
  sciChartSurface.yAxes.add(new NumericAxis(wasmContext));

  const xValues = [];
  const yValues = [];
  for(let i = 0; i < 100; i++) {
    xValues.push(i);
    yValues.push(Math.sin(i * 0.1));
  }

  // #region ExampleB
  // The ScatterPaletteProvider we created before is applied to a XyScatterRenderableSeries
  const scatterSeries = new XyScatterRenderableSeries(wasmContext, {
    dataSeries: new XyDataSeries(wasmContext, { xValues, yValues }),
    pointMarker: new EllipsePointMarker(wasmContext, {
      width: 7,
      height: 7,
      strokeThickness: 1,
      fill: "steelblue",
      stroke: "LightSteelBlue",
    }),
    // PaletteProvider feature allows coloring per-point based on a rule
    paletteProvider: new ScatterPaletteProvider("Red", "Purple", yValue => yValue > 0.0)
  });

  sciChartSurface.renderableSeries.add(scatterSeries);

  // Add this label & annotation to the chart
  sciChartSurface.annotations.add(new HorizontalLineAnnotation({ y1: 0, stroke: "#EC0F6C",
    axisLabelFill: "White",
    labelPlacement: ELabelPlacement.BottomRight, labelValue: "Values above this line are red",
    showLabel: true}));
  // #endregion
};

drawScatterChartWithPalette("scichart-root");




async function builderExample(divElementId) {
  // Demonstrates how to create a chart with a custom PaletteProvider, using the builder API
  const {
    chartBuilder,
    EBaseType,
    ESeriesType,
    EPaletteProviderType,
    EThemeProviderType,
    EPointMarkerType,
    EAnnotationType,
    ELabelPlacement
  } = SciChart;

  // or, for npm, import { chartBuilder, ... } from "scichart"

  const xValues = [];
  const yValues = [];
  for(let i = 0; i < 100; i++) {
    xValues.push(i);
    yValues.push(Math.sin(i * 0.1));
  }

  // #region ExampleC
  // Register the custom ScatterPaletteProvider with the chartBuilder
  chartBuilder.registerType(EBaseType.PaletteProvider, "ScatterPaletteProvider",
      (options) => new ScatterPaletteProvider(options.stroke, options.fill, options.rule));

  // Use the Builder-API to build the chart and apply a paletteprovider
  const { wasmContext, sciChartSurface } = await chartBuilder.build2DChart(divElementId, {
    surface: { theme: { type: EThemeProviderType.Dark } },
    series: [
      {
        type: ESeriesType.ScatterSeries,
        xyData: {
          xValues,
          yValues,
        },
        options: {
          stroke: "White",
          strokeThickness: 5,
          pointMarker: {
            type: EPointMarkerType.Ellipse,
            options: { width: 7,
              height: 7,
              strokeThickness: 1,
              fill: "steelblue",
              stroke: "LightSteelBlue"
            }
          },
          // Now you can instantiate using parameters below
          paletteProvider: {
            type: EPaletteProviderType.Custom,
            customType: "ScatterPaletteProvider",
            options: {
              stroke: "Red",
              fill: "Purple",
              rule: (yValue) => yValue >= 0.0,
            }
          }
          // Note: Assigning an instance is also valid, e.g.
          // paletteProvider: new ScatterPaletteProvider("Green", "Red", yValue => yValue >= 4.0)
        }
      }
    ],
    annotations: [
      { type: EAnnotationType.RenderContextHorizontalLineAnnotation, options: {
          y1: 0, stroke: "#EC0F6C",
          axisLabelFill: "White",
          labelPlacement: ELabelPlacement.BottomRight, labelValue: "Values above this line are red",
          showLabel: true
        }
      }
    ]
  });
  // #endregion
};




// Uncomment this to use the builder example
//builderExample("scichart-root");